
/***************************************************************************
 *   jell - library                                                        *
 *                                                                         *
 *   Copyright (C) 2008 by kuerant                                         *
 *                         <kuerant@gmail.com>                             *
 *                                                                         *
 *   This library is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU Library General Public License as       *
 *   published by the Free Software Foundation; either version 2 of the    *
 *   License, or (at your option) any later version.                       *
 *                                                                         *
 *   This library is distributed in the hope that it will be usefull, but  *
 *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      *
 *   Library General Public License for more details.                      *
 *                                                                         *
 *   You should have received a copy of the GNU Library General Public     *
 *   License along with this library; if not, write to the Free Software   *
 *   Foundation, Inc., 59 Temple Place - Suite 330, Boston,                *
 *   MA 02111-1307, USA                                                    *
 ***************************************************************************/

#include <cstring>
#include <cstdlib>

#include "jell/jell_address.hpp"

namespace   jell
{
    JellAddress::JellAddress()
        : m_uri(""), m_port(0)
    {
    }

    JellAddress::JellAddress(const std::string& uri)
        : m_uri(uri), m_port(0)
    {
        this->parse( uri );
    }

    JellAddress::JellAddress(JellAddress& rhs)
        : m_uri(rhs.m_uri),
          m_protocol(rhs.m_protocol),
          m_hostname(rhs.m_hostname), m_port(rhs.m_port),
          m_path(rhs.m_path), m_query(rhs.m_query), m_anchor(rhs.m_anchor)
    {
    }

    JellAddress::JellAddress(const JellAddress& rhs)
        : m_uri(rhs.m_uri),
          m_protocol(rhs.m_protocol),
          m_hostname(rhs.m_hostname), m_port(rhs.m_port),
          m_path(rhs.m_path), m_query(rhs.m_query), m_anchor(rhs.m_anchor)
    {
    }

    JellAddress&
    JellAddress::operator=(const std::string uri)
    {
        m_uri = uri;
        m_port = 0;

        this->parse( uri );
    }

    JellAddress&
    JellAddress::operator=(const JellAddress& rhs)
    {
        m_uri = rhs.m_uri;

        m_protocol = rhs.m_protocol;
        m_hostname = rhs.m_hostname;
        m_port     = rhs.m_port;
        m_path     = rhs.m_path;
        m_query    = rhs.m_query;
        m_anchor   = rhs.m_anchor;
    }

    JellAddress&
    JellAddress::operator=(JellAddress& rhs)
    {
        m_uri = rhs.m_uri;

        m_protocol = rhs.m_protocol;
        m_hostname = rhs.m_hostname;
        m_port     = rhs.m_port;
        m_path     = rhs.m_path;
        m_query    = rhs.m_query;
        m_anchor   = rhs.m_anchor;

        return  *this;
    }

    ///////////////////////////////////////////////////////////////////

    /** Parse the JellAddress.
     *
     * Parse the JellAddress into the protocol, the hostname, the path and the paramters with their values
     */
    void JellAddress::parse (const std::string& uri)
    {
        /* format example
         * protocol://hostname:port/path/path/path.pl?param1=value1&amp;param2=value2
         * we include the script name in the path, so the path would be /path/path/path.pl in this example
         *  &amp; could also be &
         */

        //1. Init
        const char* uriPtr = uri.c_str();
        int pos = 0;

        m_protocol = "";
        m_hostname = "";
        m_path = "";
        m_query = "";
        m_anchor = "";

        // 2. Get the protocol, which is from the begining to the first ://
        bool checkHostname = true;
        const char* end = strchr( uriPtr, ':' );
        if (end) { //protocol was found
            m_protocol.append(uriPtr, end-uriPtr);
            uriPtr = end + 1;

            //find the end of the protocol separator (e.g. "://")
            ////for (; (*uriPtr == ':') || (*uriPtr == '/'); uriPtr++);
            uriPtr++, uriPtr++; // for "://"
            if ('/' == *uriPtr) {
                // for "file:///tmp/abc.txt"
                checkHostname = false;
            }
        }

        //3.Get the hostname part. This is the part from pos up to the first slash
        bool checkPath   = true;
        bool checkParams = true;
        bool checkAnchor = true;

        end = strchr(uriPtr, '/');
        if (!end) {
            checkPath = false;
            end = strchr(uriPtr, '?');
        }
        if (!end) {
            checkParams = false;
            end = strchr(uriPtr, '#');
        }
        if (!end) {
            checkAnchor = false;
            end = uriPtr+strlen(uriPtr);
        }

        if (checkHostname) {
            const char* _end_hostname = strchr(uriPtr, ':');
            if (!_end_hostname) {
                m_hostname.append(uriPtr, end-uriPtr);
            }
            else {
                m_hostname.append(uriPtr, _end_hostname - uriPtr);
                m_port = atoi(_end_hostname + 1);
            }

            uriPtr = end + ((*end)? 1 : 0);
        }

        if (checkPath) {
            // path should begin with '/'
            while( '/' != *uriPtr ) --uriPtr;

            end = strchr(uriPtr, '?');
            if (!end) {
                checkParams = false;
                end = strchr(uriPtr, '#');
            }
            if (!end) {
                checkAnchor = false;
                end = uriPtr+strlen(uriPtr);
            }

            m_path.append(uriPtr, end-uriPtr);

            uriPtr = end + ((*end)? 1 : 0);
        }

        if (checkParams) {
            end = strchr(uriPtr, '#');
            if (!end) {
                checkAnchor = false;
                end = uriPtr+strlen(uriPtr);
            }

            m_query.append(uriPtr, end - uriPtr);

            uriPtr = end + ((*end) ? 1 : 0);
        }

        if (checkAnchor) {
            m_anchor.append( uriPtr );
        }
    }   // parse()

}   // namespace jell

